package bsh;

import java.util.LinkedList;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import bsh.AssignmentNodeCompiler.AssignmentTarget;
import bsh.asm.acessor.LocalObjectAccessor;
import bsh.asm.acessor.ObjectAccessor;
import bsh.asm.acessor.ThisFieldObjectAcessor;
import bsh.exception.CompilationFailedException;
import bsh.meta.TypeWrapper;

/**
 * {@link AssignmentTarget}
 * 
 * @author takeshi
 */
public class AmbiguousNameAssignmentTarget implements AssignmentTarget {

    private final LinkedList<ObjectAccessor> list;

    /**
     * @param line numero da linha
     * @param text o text
     * @param state {@link CompilationState}
     * @param unit {@link CompilationUnit}
     * @throws CompilationFailedException e
     */
    public AmbiguousNameAssignmentTarget(int line, String text, CompilationState state, CompilationUnit unit) throws CompilationFailedException {
        this.list = AmbiguosNameCompiler.resolveAccessorsFor(line, text, state.currentScope(), unit);
        ObjectAccessor last = this.list.getFirst();
        if (last instanceof ThisFieldObjectAcessor) {
            ThisFieldObjectAcessor acc = (ThisFieldObjectAcessor) last;
            this.list.removeFirst();
            this.list.addFirst(acc.getFieldAccessor());
            this.list.addFirst(acc.getThisAccessor());
        }
    }

    /**
     * {@inheritDoc}
     */
    public void doAssign(MethodVisitor visitor, CompilationState state) throws CompilationFailedException {
        this.list.getLast().storeObject(visitor, state);
    }

    /**
     * {@inheritDoc}
     */
    public void load(MethodVisitor visitor, CompilationState state) throws CompilationFailedException {
        this.list.getLast().loadObject(visitor, state);
    }

    /**
     * {@inheritDoc}
     */
    public void prepare(MethodVisitor visitor, CompilationState state) throws CompilationFailedException {
        ObjectAccessor last = this.list.getLast();
        for (ObjectAccessor acc : this.list) {
            if (acc != last) {
                acc.loadObject(visitor, state);
            }
        }
        last.preStore(visitor, state);
    }

    /**
     * {@inheritDoc}
     */
    public void dup(MethodVisitor visitor, CompilationState state) throws CompilationFailedException {
        if (this.list.size() > 1) {
            state.pushStack(state.peekStack());
            visitor.visitInsn(Opcodes.DUP);
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean isLocal() {
        return this.list.size() == 1 && this.list.peek() instanceof LocalObjectAccessor;
    }

    /**
     * {@inheritDoc}
     */
    public TypeWrapper type() {
        return this.list.getLast().type();
    }

    /**
     * @return {@link LinkedList} {@link ObjectAccessor}
     */
    public LinkedList<ObjectAccessor> getList() {
        return list;
    }

}
